home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / util4 / bytmrk20.lha / emfloat.c < prev    next >
C/C++ Source or Header  |  1995-11-03  |  35KB  |  1,266 lines

  1.  
  2.  
  3. #include <stdio.h>
  4. #include "nmglobal.h"
  5. #include "emfloat.h"
  6.  
  7. /*
  8. ** emfloat.c
  9. ** BYTEmark (tm)
  10. ** BYTE's Native Mode Benchmarks
  11. ** Rick Grehan, BYTE Magazine.
  12. */
  13.  
  14. #ifndef MAC
  15. #include <mem.h>
  16. #endif
  17.  
  18. /*
  19. ** Floating-point emulator.
  20. ** These routines are only "sort of" IEEE-compliant.  All work is
  21. ** done using an internal representation.  Also, the routines do
  22. ** not check for many of the exceptions that might occur.
  23. ** Still, the external formats produced are IEEE-compatible,
  24. ** with the restriction that they presume a low-endian machine
  25. ** (though the endianism will not effect the performance).
  26. **
  27. ** Some code here was based on work done by Steve Snelgrove of
  28. ** Orem, UT.  Other code comes from routines presented in
  29. ** the long-ago book: "Microprocessor Programming for
  30. ** Computer Hobbyists" by Neill Graham.
  31. */
  32.  
  33. /**************************
  34. ** SetupCPUEmFloatArrays **
  35. ***************************
  36. ** Set up the arrays that will be used in the emulated
  37. ** floating-point tests.
  38. ** This is done by loading abase and bbase elements with
  39. ** random numbers.  We use our long-to-floating point
  40. ** routine to set them up.
  41. ** NOTE: We really don't need the pointer to cbase...cbase
  42. ** is overwritten in the benchmark.
  43. */
  44. void SetupCPUEmFloatArrays(InternalFPF *abase,
  45.                 InternalFPF *bbase,
  46.                 InternalFPF *cbase,
  47.                 ulong arraysize)
  48. {
  49. ulong i;
  50. InternalFPF locFPF1,locFPF2;
  51.  
  52. for(i=0;i<arraysize;i++)
  53. {       LongToInternalFPF(randwc(50000L),&locFPF1);
  54.         LongToInternalFPF(randwc(50000L)+1L,&locFPF2);
  55.         DivideInternalFPF(&locFPF1,&locFPF2,abase+i);
  56.         LongToInternalFPF(randwc(50000L)+1L,&locFPF2);
  57.         DivideInternalFPF(&locFPF1,&locFPF2,bbase+i);
  58. }
  59. return;
  60. }
  61.  
  62. /***********************
  63. ** DoEmFloatIteration **
  64. ************************
  65. ** Perform an iteration of the emulated floating-point
  66. ** benchmark.  Note that "an iteration" can involve multiple
  67. ** loops through the benchmark.
  68. */
  69. ulong DoEmFloatIteration(InternalFPF *abase,
  70.                 InternalFPF *bbase,
  71.                 InternalFPF *cbase,
  72.                 ulong arraysize, ulong loops)
  73. {
  74. ulong elapsed;          /* For the stopwatch */
  75. static uchar jtable[16] = {0,0,0,0,1,1,1,1,2,2,2,2,2,3,3,3};
  76. ulong i;
  77.  
  78. /*
  79. ** Begin timing
  80. */
  81. elapsed=StartStopwatch();
  82.  
  83. /*
  84. ** Each pass through the array performs operations in
  85. ** the followingratios:
  86. **   4 adds, 4 subtracts, 5 multiplies, 3 divides
  87. ** (adds and subtracts being nearly the same operation)
  88. */
  89. while(loops--)
  90. {
  91.         for(i=0;i<arraysize;i++)
  92.                 switch(jtable[i % 16])
  93.                 {
  94.                         case 0: /* Add */       
  95.                                 AddSubInternalFPF(0,abase+i,
  96.                                   bbase+i,
  97.                                   cbase+i);
  98.                                 break;
  99.                         case 1: /* Subtract */
  100.                                 AddSubInternalFPF(1,abase+i,
  101.                                   bbase+i,
  102.                                   cbase+i);
  103.                                 break;
  104.                         case 2: /* Multiply */
  105.                                 MultiplyInternalFPF(abase+i,
  106.                                   bbase+i,
  107.                                   cbase+i);
  108.                                 break;
  109.                         case 3: /* Divide */
  110.                                 DivideInternalFPF(abase+i,
  111.                                   bbase+i,
  112.                                   cbase+i);
  113.                                 break;
  114.                 }
  115. }
  116.  
  117. return(StopStopwatch(elapsed));
  118. }
  119.  
  120. /***********************
  121. ** SetInternalFPFZero **
  122. ************************
  123. ** Set an internal floating-point-format number to zero.
  124. ** sign determines the sign of the zero.
  125. */
  126. static void SetInternalFPFZero(InternalFPF *dest,
  127.                         uchar sign)
  128. {
  129. int i;          /* Index */
  130.  
  131. dest->type=IFPF_IS_ZERO;
  132. dest->sign=sign;
  133. dest->exp=MIN_EXP;
  134. for(i=0;i<INTERNAL_FPF_PRECISION;i++)
  135.         dest->mantissa[i]=0;
  136. return;
  137. }
  138.  
  139. /***************************
  140. ** SetInternalFPFInfinity **
  141. ****************************
  142. ** Set an internal floating-point-format number to infinity.
  143. ** This can happen if the exponent exceeds MAX_EXP.
  144. ** As above, sign picks the sign of infinity.
  145. */
  146. static void SetInternalFPFInfinity(InternalFPF *dest,
  147.                         uchar sign)
  148. {
  149. int i;          /* Index */
  150.  
  151. dest->type=IFPF_IS_INFINITY;
  152. dest->sign=sign;
  153. dest->exp=MIN_EXP;
  154. for(i=0;i<INTERNAL_FPF_PRECISION;i++)
  155.         dest->mantissa[i]=0;
  156. return;
  157. }
  158.  
  159. /**********************
  160. ** SetInternalFPFNaN **
  161. ***********************
  162. ** Set an internal floating-point-format number to Nan
  163. ** (not a number).  Note that we "emulate" an 80x87 as far
  164. ** as the mantissa bits go.
  165. */
  166. static void SetInternalFPFNaN(InternalFPF *dest)
  167. {
  168. int i;          /* Index */
  169.  
  170. dest->type=IFPF_IS_NAN;
  171. dest->exp=MAX_EXP;
  172. dest->sign=1;
  173. dest->mantissa[0]=0x4000;
  174. for(i=1;i<INTERNAL_FPF_PRECISION;i++)
  175.         dest->mantissa[i]=0;
  176.  
  177. return;
  178. }
  179.  
  180. /*******************
  181. ** IsMantissaZero **
  182. ********************
  183. ** Pass this routine a pointer to an internal floating point format
  184. ** number's mantissa.  It checks for an all-zero mantissa.
  185. ** Returns 0 if it is NOT all zeros, !=0 otherwise.
  186. */
  187. static int IsMantissaZero(u16 *mant)
  188. {
  189. int i;          /* Index */
  190. int n;          /* Return value */
  191.  
  192. n=0;
  193. for(i=0;i<INTERNAL_FPF_PRECISION;i++)
  194.         n|=mant[i];
  195.  
  196. return(!n);
  197. }
  198.  
  199. /**************
  200. ** Add16Bits **
  201. ***************
  202. ** Add b, c, and carry.  Retult in a.  New carry in carry.
  203. */
  204. static void Add16Bits(u16 *carry,
  205.                 u16 *a,
  206.                 u16 b,
  207.                 u16 c)
  208. {
  209. u32 accum;              /* Accumulator */
  210.  
  211. /*
  212. ** Do the work in the 32-bit accumulator so we can return
  213. ** the carry.
  214. */
  215. accum=(u32)b;
  216. accum+=(u32)c;
  217. accum+=(u32)*carry;
  218. *carry=(u16)((accum & 0x00010000) ? 1 : 0);     /* New carry */
  219. *a=(u16)(accum & 0xFFFF);       /* Result is lo 16 bits */
  220. return;
  221. }
  222.  
  223. /**************
  224. ** Sub16Bits **
  225. ***************
  226. ** Additive inverse of above.
  227. */
  228. static void Sub16Bits(u16 *borrow,
  229.                 u16 *a,
  230.                 u16 b,
  231.                 u16 c)
  232. {
  233. u32 accum;              /* Accumulator */
  234.  
  235. accum=(u32)b;
  236. accum-=(u32)c;
  237. accum-=(u32)*borrow;
  238. *borrow=(u32)((accum & 0x00010000) ? 1 : 0);    /* New borrow */
  239. *a=(u16)(accum & 0xFFFF);
  240. return;
  241. }
  242.  
  243. /*******************
  244. ** ShiftMantLeft1 **
  245. ********************
  246. ** Shift a vector of 16-bit numbers left 1 bit.  Also provides
  247. ** a carry bit, which is shifted in at the beginning, and
  248. ** shifted out at the end.
  249. */
  250. static void ShiftMantLeft1(u16 *carry,
  251.                         u16 *mantissa)
  252. {
  253. int i;          /* Index */
  254. int new_carry;
  255. u16 accum;      /* Temporary holding placed */
  256.  
  257. for(i=INTERNAL_FPF_PRECISION-1;i>=0;i--)
  258. {       accum=mantissa[i];
  259.         new_carry=accum & 0x8000;       /* Get new carry */
  260.         accum=accum<<1;                 /* Do the shift */
  261.         if(*carry)
  262.                 accum|=1;               /* Insert previous carry */
  263.         *carry=new_carry;
  264.         mantissa[i]=accum;              /* Return shifted value */
  265. }
  266. return;
  267. }
  268.  
  269. /********************
  270. ** ShiftMantRight1 **
  271. *********************
  272. ** Shift a mantissa right by 1 bit.  Provides carry, as
  273. ** above
  274. */
  275. static void ShiftMantRight1(u16 *carry,
  276.                         u16 *mantissa)
  277. {
  278. int i;          /* Index */
  279. int new_carry;
  280. u16 accum;
  281.  
  282. for(i=0;i<INTERNAL_FPF_PRECISION;i++)
  283. {       accum=mantissa[i];
  284.         new_carry=accum & 1;            /* Get new carry */
  285.         accum=accum>>1;
  286.         if(*carry)
  287.                 accum|=0x8000;
  288.         *carry=new_carry;
  289.         mantissa[i]=accum;
  290. }
  291. return;
  292. }
  293.  
  294.  
  295. /*****************************
  296. ** StickyShiftMantRight **
  297. ******************************
  298. ** This is a shift right of the mantissa with a "sticky bit".
  299. ** I.E., if a carry of 1 is shifted out of the least significant
  300. ** bit, the least significant bit is set to 1.
  301. */
  302. static void StickyShiftRightMant(InternalFPF *ptr,
  303.                         int amount)
  304. {
  305. int i;          /* Index */
  306. u16 carry;      /* Self-explanatory */
  307. u16 *mantissa;
  308.  
  309. mantissa=ptr->mantissa;
  310.  
  311. if(ptr->type!=IFPF_IS_ZERO)     /* Don't bother shifting a zero */
  312. {
  313.         /*
  314.         ** If the amount of shifting will shift everyting
  315.         ** out of existence, then just clear the whole mantissa
  316.         ** and set the lowmost bit to 1.
  317.         */
  318.         if(amount>=INTERNAL_FPF_PRECISION * 16)
  319.         {
  320.                 for(i=0;i<INTERNAL_FPF_PRECISION-1;i++)
  321.                         mantissa[i]=0;
  322.                 mantissa[INTERNAL_FPF_PRECISION-1]=1;
  323.         }
  324.         else
  325.                 for(i=0;i<amount;i++)
  326.                 {
  327.                         carry=0;
  328.                         ShiftMantRight1(&carry,mantissa);
  329.                         if(carry)
  330.                                 mantissa[INTERNAL_FPF_PRECISION-1] |= 1;
  331.                 }
  332. }
  333. return;
  334. }
  335.  
  336.  
  337. /**************************************************
  338. **         POST ARITHMETIC PROCESSING            **
  339. **  (NORMALIZE, ROUND, OVERFLOW, AND UNDERFLOW)  **
  340. **************************************************/
  341.  
  342. /**************
  343. ** normalize **
  344. ***************
  345. ** Normalize an internal-representation number.  Normalization
  346. ** discards empty most-significant bits.
  347. */
  348. static void normalize(InternalFPF *ptr)
  349. {
  350. u16     carry;
  351.  
  352. /*
  353. ** As long as there's a highmost 0 bit, shift the significand
  354. ** left 1 bit.  Each time you do this, though, you've
  355. ** gotta decrement the exponent.
  356. */
  357. while ((ptr->mantissa[0] & 0x8000) == 0)
  358. {
  359.         carry = 0;
  360.         ShiftMantLeft1(&carry, ptr->mantissa);
  361.         ptr->exp--;
  362. }
  363. return;
  364. }
  365.  
  366. /****************
  367. ** denormalize **
  368. *****************
  369. ** Denormalize an internal-representation number.  This means
  370. ** shifting it right until its exponent is equivalent to
  371. ** minimum_exponent. (You have to do this often in order
  372. ** to perform additions and subtractions).
  373. */
  374. static void denormalize(InternalFPF *ptr,
  375.                 int minimum_exponent)
  376. {
  377. long exponent_difference;
  378.  
  379. if (IsMantissaZero(ptr->mantissa))
  380. {
  381.         printf("Error:  zero significand in denormalize\n");
  382. }
  383.  
  384. exponent_difference = ptr->exp-minimum_exponent;
  385. if (exponent_difference < 0)
  386. {
  387.         /* 
  388.         ** The number is subnormal
  389.         */
  390.         exponent_difference = -exponent_difference;
  391.         if (exponent_difference >= (INTERNAL_FPF_PRECISION * 16))
  392.         {
  393.                 /* Underflow */
  394.                 SetInternalFPFZero(ptr, ptr->sign);
  395.         }
  396.         else
  397.         {
  398.                 ptr->exp+=exponent_difference;
  399.                 StickyShiftRightMant(ptr, exponent_difference);
  400.         }
  401. }
  402. return;
  403. }
  404.  
  405.  
  406. /*********************
  407. ** RoundInternalFPF **
  408. **********************
  409. ** Round an internal-representation number.
  410. ** The kind of rounding we do here is simplest...referred to as
  411. ** "chop".  "Extraneous" rightmost bits are simply hacked off.
  412. */
  413. void RoundInternalFPF(InternalFPF *ptr)
  414. {
  415. /* int i; */
  416.  
  417. if (ptr->type == IFPF_IS_NORMAL ||
  418.         ptr->type == IFPF_IS_SUBNORMAL)
  419. {
  420.         denormalize(ptr, MIN_EXP);
  421.         if (ptr->type != IFPF_IS_ZERO)
  422.         {
  423.         
  424.                 /* clear the extraneous bits */
  425.                 ptr->mantissa[3] &= 0xfff8;
  426. /*              for (i=4; i<INTERNAL_FPF_PRECISION; i++)
  427.                 {
  428.                         ptr->mantissa[i] = 0;
  429.                 }
  430. */
  431.                 /*
  432.                 ** Check for overflow
  433.                 */
  434.                 if (ptr->exp > MAX_EXP)
  435.                 {
  436.                         SetInternalFPFInfinity(ptr, ptr->sign);
  437.                 }
  438.         }
  439. }
  440. return;
  441. }
  442.  
  443. /*******************************************************
  444. **  ARITHMETIC OPERATIONS ON INTERNAL REPRESENTATION  **
  445. *******************************************************/
  446.  
  447. /***************
  448. ** choose_nan **
  449. ****************
  450. ** Called by routines that are forced to perform math on
  451. ** a pair of NaN's.  This routine "selects" which NaN is
  452. ** to be returned.
  453. */
  454. static void choose_nan(InternalFPF *x,
  455.                 InternalFPF *y,
  456.                 InternalFPF *z,
  457.                 int intel_flag)
  458. {
  459. int i;
  460.  
  461. /*
  462. ** Compare the two mantissas,
  463. ** return the larger.  Note that we will be emulating
  464. ** an 80387 in this operation.
  465. */
  466. for (i=0; i<INTERNAL_FPF_PRECISION; i++)
  467. {
  468.         if (x->mantissa[i] > y->mantissa[i])
  469.         {
  470.                 memmove((void *)x,(void *)z,sizeof(InternalFPF));
  471.                 return;
  472.         }
  473.         if (x->mantissa[i] < y->mantissa[i])
  474.         {
  475.                 memmove((void *)y,(void *)z,sizeof(InternalFPF));
  476.                 return;
  477.         }
  478. }
  479.  
  480. /* 
  481. ** They are equal
  482. */
  483. if (!intel_flag)
  484.         /* if the operation is addition */
  485.         memmove((void *)x,(void *)z,sizeof(InternalFPF));
  486. else
  487.         /* if the operation is multiplication */
  488.         memmove((void *)y,(void *)z,sizeof(InternalFPF));
  489. return;
  490. }
  491.  
  492.  
  493. /**********************
  494. ** AddSubInternalFPF **
  495. ***********************
  496. ** Adding or subtracting internal-representation numbers.
  497. ** Internal-representation numbers pointed to by x and y are
  498. ** added/subtracted and the result returned in z.
  499. */
  500. static void AddSubInternalFPF(uchar operation,
  501.                 InternalFPF *x,
  502.                 InternalFPF *y,
  503.                 InternalFPF *z)
  504. {
  505. int exponent_difference;
  506. u16 borrow;
  507. u16 carry;
  508. int i;
  509. InternalFPF locx,locy;  /* Needed since we alter them */
  510.  
  511. /*
  512. ** Following big switch statement handles the
  513. ** various combinations of operand types.
  514. */
  515. switch ((x->type * IFPF_TYPE_COUNT) + y->type)
  516. {
  517. case ZERO_ZERO:
  518.         memmove((void *)x,(void *)z,sizeof(InternalFPF));
  519.         if (x->sign ^ y->sign ^ operation)
  520.         {
  521.                 z->sign = 0; /* positive */
  522.         }
  523.         break;
  524.  
  525. case NAN_ZERO:
  526. case NAN_SUBNORMAL:
  527. case NAN_NORMAL:
  528. case NAN_INFINITY:
  529. case SUBNORMAL_ZERO:
  530. case NORMAL_ZERO:
  531. case INFINITY_ZERO:
  532. case INFINITY_SUBNORMAL:
  533. case INFINITY_NORMAL:
  534.         memmove((void *)x,(void *)z,sizeof(InternalFPF));
  535.         break;
  536.  
  537.  
  538. case ZERO_NAN:
  539. case SUBNORMAL_NAN:
  540. case NORMAL_NAN:
  541. case INFINITY_NAN:
  542.         memmove((void *)y,(void *)z,sizeof(InternalFPF));
  543.         break;
  544.  
  545. case ZERO_SUBNORMAL:
  546. case ZERO_NORMAL:
  547. case ZERO_INFINITY:
  548. case SUBNORMAL_INFINITY:
  549. case NORMAL_INFINITY:
  550.         memmove((void *)y,(void *)z,sizeof(InternalFPF));
  551.         z->sign ^= operation;
  552.         break;
  553.  
  554. case SUBNORMAL_SUBNORMAL:
  555. case SUBNORMAL_NORMAL:
  556. case NORMAL_SUBNORMAL:
  557. case NORMAL_NORMAL:
  558.         /*
  559.         ** Copy x and y to locals, since we may have
  560.         ** to alter them.
  561.         */
  562.         memmove((void *)&locx,(void *)x,sizeof(InternalFPF));
  563.         memmove((void *)&locy,(void *)y,sizeof(InternalFPF));
  564.  
  565.         /* compute sum/difference */
  566.         exponent_difference = locx.exp-locy.exp;
  567.         if (exponent_difference == 0)
  568.         {
  569.                 /* 
  570.                 ** locx.exp == locy.exp
  571.                 ** so, no shifting required
  572.                 */
  573.                 if (locx.type == IFPF_IS_SUBNORMAL ||
  574.                   locy.type == IFPF_IS_SUBNORMAL)
  575.                         z->type = IFPF_IS_SUBNORMAL;
  576.                 else
  577.                         z->type = IFPF_IS_NORMAL;
  578.  
  579.                 /* 
  580.                 ** Assume that locx.mantissa > locy.mantissa
  581.                 */
  582.                 z->sign = locx.sign;
  583.                 z->exp= locx.exp;
  584.         }
  585.         else
  586.                 if (exponent_difference > 0)
  587.                 {
  588.                         /*
  589.                         ** locx.exp > locy.exp
  590.                         */
  591.                         StickyShiftRightMant(&locy,
  592.                                  exponent_difference);
  593.                         z->type = locx.type;
  594.                         z->sign = locx.sign;
  595.                         z->exp = locx.exp;
  596.                 }
  597.                 else    /* if (exponent_difference < 0) */
  598.                 {
  599.                         /*
  600.                         ** locx.exp < locy.exp
  601.                         */
  602.                         StickyShiftRightMant(&locx,
  603.                                 -exponent_difference);
  604.                         z->type = locy.type;
  605.                         z->sign = locy.sign ^ operation;
  606.                         z->exp = locy.exp;
  607.                 }
  608.  
  609.                 if (locx.sign ^ locy.sign ^ operation)
  610.                 {
  611.                         /* 
  612.                         ** Signs are different, subtract mantissas
  613.                         */
  614.                         borrow = 0;
  615.                         for (i=(INTERNAL_FPF_PRECISION-1); i>=0; i--)
  616.                                 Sub16Bits(&borrow,
  617.                                         &z->mantissa[i],
  618.                                         locx.mantissa[i],
  619.                                         locy.mantissa[i]);
  620.  
  621.                         if (borrow)
  622.                         {
  623.                                 /* The y->mantissa was larger than the
  624.                                 ** x->mantissa leaving a negative
  625.                                 ** result.  Change the result back to
  626.                                 ** an unsigned number and flip the
  627.                                 ** sign flag.
  628.                                 */
  629.                                 z->sign = locy.sign ^ operation;
  630.                                 borrow = 0;
  631.                                 for (i=(INTERNAL_FPF_PRECISION-1); i>=0; i--)
  632.                                 {
  633.                                         Sub16Bits(&borrow,
  634.                                                 &z->mantissa[i],
  635.                                                 0,
  636.                                                 z->mantissa[i]);
  637.                                 }
  638.                         }
  639.                         else
  640.                         {
  641.                                 /* The assumption made above
  642.                                 ** (i.e. x->mantissa >= y->mantissa)
  643.                                 ** was correct.  Therefore, do nothing.
  644.                                 ** z->sign = x->sign;
  645.                                 */
  646.                         }
  647.  
  648.                         if (IsMantissaZero(z->mantissa))
  649.                         {
  650.                                 z->type = IFPF_IS_ZERO;
  651.                                 z->sign = 0; /* positive */
  652.                         }
  653.                         else
  654.                                 if (locx.type == IFPF_IS_NORMAL ||
  655.                                          locy.type == IFPF_IS_NORMAL)
  656.                                 {
  657.                                         normalize(z);
  658.                                 }
  659.                 }
  660.                 else
  661.                 {
  662.                         /* signs are the same, add mantissas */
  663.                         carry = 0;
  664.                         for (i=(INTERNAL_FPF_PRECISION-1); i>=0; i--)
  665.                         {
  666.                                 Add16Bits(&carry,
  667.                                         &z->mantissa[i],
  668.                                         locx.mantissa[i],
  669.                                         locy.mantissa[i]);
  670.                         }
  671.  
  672.                         if (carry)
  673.                         {
  674.                                 z->exp++;
  675.                                 carry=0;
  676.                                 ShiftMantRight1(&carry,z->mantissa);
  677.                                 z->mantissa[0] |= 0x8000;
  678.                                 z->type = IFPF_IS_NORMAL;
  679.                         }
  680.                         else
  681.                                 if (z->mantissa[0] & 0x8000)
  682.                                         z->type = IFPF_IS_NORMAL;
  683.         }
  684.         break;
  685.  
  686. case INFINITY_INFINITY:
  687.         SetInternalFPFNaN(z);
  688.         break;
  689.  
  690. case NAN_NAN:
  691.         choose_nan(x, y, z, 1);
  692.         break;
  693. }
  694.  
  695. /*
  696. ** All the math is done; time to round.
  697. */
  698. RoundInternalFPF(z);
  699. return;
  700. }
  701.  
  702.  
  703. /************************
  704. ** MultiplyInternalFPF **
  705. *************************
  706. ** Two internal-representation numbers x and y are multiplied; the
  707. ** result is returned in z.
  708. */
  709. static void MultiplyInternalFPF(InternalFPF *x,
  710.                         InternalFPF *y,
  711.                         InternalFPF *z)
  712. {
  713. int i;
  714. int j;
  715. u16 carry;
  716. u16 extra_bits[INTERNAL_FPF_PRECISION];
  717. InternalFPF locy;       /* Needed since this will be altered */
  718. /*
  719. ** As in the preceding function, this large switch
  720. ** statement selects among the many combinations
  721. ** of operands.
  722. */
  723. switch ((x->type * IFPF_TYPE_COUNT) + y->type)
  724. {
  725. case INFINITY_SUBNORMAL:
  726. case INFINITY_NORMAL:
  727. case INFINITY_INFINITY:
  728. case ZERO_ZERO:
  729. case ZERO_SUBNORMAL:
  730. case ZERO_NORMAL:
  731.         memmove((void *)x,(void *)z,sizeof(InternalFPF));
  732.         z->sign ^= y->sign;
  733.         break;
  734.  
  735. case SUBNORMAL_INFINITY:
  736. case NORMAL_INFINITY:
  737. case SUBNORMAL_ZERO:
  738. case NORMAL_ZERO:
  739.         memmove((void *)y,(void *)z,sizeof(InternalFPF));
  740.         z->sign ^= x->sign;
  741.         break;
  742.  
  743. case ZERO_INFINITY:
  744. case INFINITY_ZERO:
  745.         SetInternalFPFNaN(z);
  746.         break;
  747.  
  748. case NAN_ZERO:
  749. case NAN_SUBNORMAL:
  750. case NAN_NORMAL:
  751. case NAN_INFINITY:
  752.         memmove((void *)x,(void *)z,sizeof(InternalFPF));
  753.         break;
  754.  
  755. case ZERO_NAN:
  756. case SUBNORMAL_NAN:
  757. case NORMAL_NAN:
  758. case INFINITY_NAN:
  759.         memmove((void *)y,(void *)z,sizeof(InternalFPF));
  760.         break;
  761.  
  762.  
  763. case SUBNORMAL_SUBNORMAL:
  764. case SUBNORMAL_NORMAL:
  765. case NORMAL_SUBNORMAL:
  766. case NORMAL_NORMAL:
  767.         /*
  768.         ** Make a local copy of the y number, since we will be
  769.         ** altering it in the process of multiplying.
  770.         */
  771.         memmove((void *)&locy,(void *)y,sizeof(InternalFPF));
  772.  
  773.         /*
  774.         ** Check for unnormal zero arguments
  775.         */
  776.         if (IsMantissaZero(x->mantissa) || IsMantissaZero(y->mantissa))
  777.                 SetInternalFPFInfinity(z, 0);
  778.  
  779.         /*
  780.         ** Initialize the result
  781.         */
  782.         if (x->type == IFPF_IS_SUBNORMAL ||
  783.             y->type == IFPF_IS_SUBNORMAL)
  784.                 z->type = IFPF_IS_SUBNORMAL;
  785.         else
  786.                 z->type = IFPF_IS_NORMAL;
  787.  
  788.         z->sign = x->sign ^ y->sign;
  789.         z->exp = x->exp + y->exp ;
  790.         for (i=0; i<INTERNAL_FPF_PRECISION; i++)
  791.         {
  792.                 z->mantissa[i] = 0;
  793.                 extra_bits[i] = 0;
  794.         }
  795.  
  796.         for (i=0; i<(INTERNAL_FPF_PRECISION*16); i++)
  797.         {
  798.                 /*
  799.                 ** Get rightmost bit of the multiplier
  800.                 */
  801.                 carry = 0;
  802.                 ShiftMantRight1(&carry, locy.mantissa);
  803.                 if (carry)
  804.                 {
  805.                         /* 
  806.                         ** Add the multiplicand to the product
  807.                         */
  808.                         carry = 0;
  809.                         for (j=(INTERNAL_FPF_PRECISION-1); j>=0; j--)
  810.                                 Add16Bits(&carry,
  811.                                         &z->mantissa[j],
  812.                                         z->mantissa[j],
  813.                                         x->mantissa[j]);
  814.                 }
  815.                 else
  816.                 {
  817.                         carry = 0;
  818.                 }
  819.  
  820.                 /* 
  821.                 ** Shift the product right.  Overflow bits get
  822.                 ** shifted into extra_bits.  We'll use it later
  823.                 ** to help with the "sticky" bit.
  824.                 */
  825.                 ShiftMantRight1(&carry, z->mantissa);
  826.                 ShiftMantRight1(&carry, extra_bits);
  827.         }
  828.  
  829.         /*
  830.         ** Normalize
  831.         ** Note that we use a "special" normalization routine
  832.         ** because we need to use the extra bits. (These are
  833.         ** bits that may have been shifted off the bottom that
  834.         ** we want to reclaim...if we can.
  835.         */
  836.         while ((z->mantissa[0] & 0x8000) == 0)
  837.         {
  838.                 carry = 0;
  839.                 ShiftMantLeft1(&carry, extra_bits);
  840.                 ShiftMantLeft1(&carry, z->mantissa);
  841.                 z->exp--;
  842.         }
  843.  
  844.         /*
  845.         ** Set the sticky bit if any bits set in extra bits.
  846.         */
  847.         if (IsMantissaZero(extra_bits))
  848.         {
  849.                 z->mantissa[INTERNAL_FPF_PRECISION-1] |= 1;
  850.         }
  851.         break;
  852.  
  853. case NAN_NAN:
  854.         choose_nan(x, y, z, 0);
  855.         break;
  856. }
  857.  
  858. /*
  859. ** All math done...do rounding.
  860. */
  861. RoundInternalFPF(z);
  862. return;
  863. }
  864.  
  865.  
  866. /**********************
  867. ** DivideInternalFPF **
  868. ***********************
  869. ** Divide internal FPF number x by y.  Return result in z.
  870. */
  871. static void DivideInternalFPF(InternalFPF *x, 
  872.                         InternalFPF *y, 
  873.                         InternalFPF *z)
  874. {
  875. int i;
  876. int j;
  877. u16 carry;
  878. u16 extra_bits[INTERNAL_FPF_PRECISION];
  879. InternalFPF locx;       /* Local for x number */
  880.  
  881. /*
  882. ** As with preceding function, the following switch
  883. ** statement selects among the various possible
  884. ** operands.
  885. */
  886. switch ((x->type * IFPF_TYPE_COUNT) + y->type)
  887. {
  888. case ZERO_ZERO:
  889. case INFINITY_INFINITY:
  890.         SetInternalFPFNaN(z);
  891.         break;
  892.  
  893. case ZERO_SUBNORMAL:
  894. case ZERO_NORMAL:
  895.         if (IsMantissaZero(y->mantissa))
  896.         {
  897.                 SetInternalFPFNaN(z);
  898.                 break;
  899.         }
  900.  
  901. case ZERO_INFINITY:
  902. case SUBNORMAL_INFINITY:
  903. case NORMAL_INFINITY:
  904.         SetInternalFPFZero(z, x->sign ^ y->sign);
  905.         break;
  906.  
  907. case SUBNORMAL_ZERO:
  908. case NORMAL_ZERO:
  909.         if (IsMantissaZero(x->mantissa))
  910.         {
  911.                 SetInternalFPFNaN(z);
  912.                 break;
  913.         }
  914.  
  915. case INFINITY_ZERO:
  916. case INFINITY_SUBNORMAL:
  917. case INFINITY_NORMAL:
  918.         SetInternalFPFInfinity(z, 0);
  919.         z->sign = x->sign ^ y->sign;
  920.         break;
  921.  
  922. case NAN_ZERO:
  923. case NAN_SUBNORMAL:
  924. case NAN_NORMAL:
  925. case NAN_INFINITY:
  926.         memmove((void *)x,(void *)z,sizeof(InternalFPF));
  927.         break;
  928.  
  929. case ZERO_NAN:
  930. case SUBNORMAL_NAN:
  931. case NORMAL_NAN:
  932. case INFINITY_NAN:
  933.         memmove((void *)y,(void *)z,sizeof(InternalFPF));
  934.         break;
  935.  
  936. case SUBNORMAL_SUBNORMAL:
  937. case NORMAL_SUBNORMAL:
  938. case SUBNORMAL_NORMAL:
  939. case NORMAL_NORMAL:
  940.         /*
  941.         ** Make local copy of x number, since we'll be
  942.         ** altering it in the process of dividing.
  943.         */
  944.         memmove((void *)&locx,(void *)x,sizeof(InternalFPF));
  945.  
  946.         /* 
  947.         ** Check for unnormal zero arguments
  948.         */
  949.         if (IsMantissaZero(locx.mantissa))
  950.         {
  951.                 if (IsMantissaZero(y->mantissa))
  952.                         SetInternalFPFNaN(z);
  953.                 else
  954.                         SetInternalFPFZero(z, 0);
  955.                 break;
  956.         }
  957.         if (IsMantissaZero(y->mantissa))
  958.         {
  959.                 SetInternalFPFInfinity(z, 0);
  960.                 break;
  961.         }
  962.  
  963.         /* 
  964.         ** Initialize the result
  965.         */
  966.         z->type = x->type;
  967.         z->sign = x->sign ^ y->sign;
  968.         z->exp = x->exp - y->exp +
  969.                         ((INTERNAL_FPF_PRECISION * 16 * 2));
  970.         for (i=0; i<INTERNAL_FPF_PRECISION; i++)
  971.         {
  972.                 z->mantissa[i] = 0;
  973.                 extra_bits[i] = 0;
  974.         }
  975.  
  976.         while ((z->mantissa[0] & 0x8000) == 0)
  977.         {
  978.                 carry = 0;
  979.                 ShiftMantLeft1(&carry, locx.mantissa);
  980.                 ShiftMantLeft1(&carry, extra_bits);
  981.  
  982.                 /* 
  983.                 ** Time to subtract yet?
  984.                 */
  985.                 if (carry == 0)
  986.                         for (j=0; j<INTERNAL_FPF_PRECISION; j++)
  987.                         {
  988.                                 if (y->mantissa[j] > extra_bits[j])
  989.                                 {
  990.                                         carry = 0;
  991.                                         goto no_subtract;
  992.                                 }
  993.                                 if (y->mantissa[j] < extra_bits[j])
  994.                                         break;
  995.                         }
  996.                 /* 
  997.                 ** Divisor (y) <= dividend (x), subtract
  998.                 */
  999.                 carry = 0;
  1000.                 for (j=(INTERNAL_FPF_PRECISION-1); j>=0; j--)
  1001.                         Sub16Bits(&carry,
  1002.                                 &extra_bits[j],
  1003.                                 extra_bits[j],
  1004.                                 y->mantissa[j]);
  1005.                 carry = 1;      /* 1 shifted into quotient */
  1006.         no_subtract:
  1007.                 ShiftMantLeft1(&carry, z->mantissa);
  1008.                 z->exp--;
  1009.         }
  1010.         break;
  1011.  
  1012. case NAN_NAN:
  1013.         choose_nan(x, y, z, 0);
  1014.         break;
  1015. }
  1016.  
  1017. /*
  1018. ** Math complete...do rounding
  1019. */
  1020. RoundInternalFPF(z);
  1021. }
  1022.  
  1023. /**********************
  1024. ** LongToInternalFPF **
  1025. ***********************
  1026. ** Convert a signed long integer into an internal FPF number.
  1027. */
  1028. static void LongToInternalFPF(long mylong,
  1029.                 InternalFPF *dest)
  1030. {
  1031. int i;          /* Index */
  1032. u16 myword;     /* Used to hold converted stuff */
  1033. /*
  1034. ** Save the sign and get the absolute value.  This will help us
  1035. ** with 64-bit machines, since we use only the lower 32
  1036. ** bits just in case.
  1037. */
  1038. if(mylong<0L)
  1039. {       dest->sign=1;
  1040.         mylong=0L-mylong;
  1041. }
  1042. else
  1043.         dest->sign=0;
  1044. /*
  1045. ** Prepare the destination floating point number
  1046. */
  1047. dest->type=IFPF_IS_NORMAL;
  1048. for(i=0;i<INTERNAL_FPF_PRECISION;i++)
  1049.         dest->mantissa[i]=0;
  1050.  
  1051. /*
  1052. ** See if we've got a zero.  If so, make the resultant FP
  1053. ** number a true zero and go home.
  1054. */
  1055. if(mylong==0)
  1056. {       dest->type=IFPF_IS_ZERO;
  1057.         dest->exp=0;
  1058.         return;
  1059. }
  1060.  
  1061. /*
  1062. ** Not a true zero.  Set the exponent to 32 (internal FPFs have
  1063. ** no bias) and load the low and high words into their proper
  1064. ** locations in the mantissa.  Then normalize.  The action of
  1065. ** normalizing slides the mantissa bits into place and sets
  1066. ** up the exponent properly.
  1067. */
  1068. dest->exp=32;
  1069. myword=(u16)((mylong >> 16) & 0xFFFFL);
  1070. dest->mantissa[0]=myword;
  1071. myword=(u16)(mylong & 0xFFFFL);
  1072. dest->mantissa[1]=myword;
  1073. normalize(dest);
  1074. return;
  1075. }
  1076.  
  1077. /************************
  1078. ** InternalFPFToString **
  1079. *************************
  1080. ** FOR DEBUG PURPOSES
  1081. ** This routine converts an internal floating point representation
  1082. ** number to a string.  Used in debugging the package.
  1083. ** Returns length of converted number.
  1084. ** NOTE: dest must point to a buffer big enough to hold the
  1085. **  result.  Also, this routine does append a null (an effect
  1086. **  of using the sprintf() function).  It also returns
  1087. **  a length count.
  1088. ** NOTE: This routine returns 5 significant digits.  Thats
  1089. **  about all I feel safe with, given the method of
  1090. **  conversion.  It should be more than enough for programmers
  1091. **  to determine whether the package is properly ported.
  1092. */
  1093. static int InternalFPFToString(char *dest,
  1094.                 InternalFPF *src)
  1095. {
  1096. InternalFPF locFPFNum;          /* Local for src (will be altered) */
  1097. InternalFPF IFPF10;             /* Floating-point 10 */
  1098. InternalFPF IFPFComp;           /* For doing comparisons */
  1099. int msign;                      /* Holding for mantissa sign */
  1100. int expcount;                   /* Exponent counter */
  1101. int ccount;                     /* Character counter */
  1102. int i,j,k;                      /* Index */
  1103. u16 carryaccum;                 /* Carry accumulator */
  1104. u16 mycarry;                    /* Local for carry */
  1105.  
  1106. /*
  1107. ** Check first for the simple things...Nan, Infinity, Zero.
  1108. ** If found, copy the proper string in and go home.
  1109. */
  1110. switch(src->type)
  1111. {
  1112.         case IFPF_IS_NAN:
  1113.                 memcpy(dest,"NaN",3);
  1114.                 return(3);
  1115.  
  1116.         case IFPF_IS_INFINITY:
  1117.                 if(src->sign==0)
  1118.                         memcpy(dest,"+Inf",4);
  1119.                 else
  1120.                         memcpy(dest,"-Inf",4);
  1121.                 return(4);
  1122.  
  1123.         case IFPF_IS_ZERO:
  1124.                 if(src->sign==0)
  1125.                         memcpy(dest,"+0",2);
  1126.                 else
  1127.                         memcpy(dest,"-0",2);
  1128.                 return(2);
  1129. }
  1130.  
  1131. /*
  1132. ** Move the internal number into our local holding area, since
  1133. ** we'll be altering it to print it out.
  1134. */
  1135. memcpy((void *)&locFPFNum,(void *)src,sizeof(InternalFPF));
  1136.  
  1137. /*
  1138. ** Set up a floating-point 10...which we'll use a lot in a minute.
  1139. */
  1140. LongToInternalFPF(10L,&IFPF10);
  1141.  
  1142. /*
  1143. ** Save the mantissa sign and make it positive.
  1144. */
  1145. msign=src->sign;
  1146. src->sign=0;
  1147.  
  1148. expcount=0;             /* Init exponent counter */
  1149.  
  1150. /*
  1151. ** See if the number is less than 10.  If so, multiply
  1152. ** the number repeatedly by 10 until it's not.   For each
  1153. ** multiplication, decrement a counter so we can keep track
  1154. ** of the exponent.
  1155. */
  1156. while(1)
  1157. {       AddSubInternalFPF(1,&locFPFNum,&IFPF10,&IFPFComp);
  1158.         if(IFPFComp.sign==0) break;
  1159.         MultiplyInternalFPF(&locFPFNum,&IFPF10,&IFPFComp);
  1160.         expcount--;
  1161.         memcpy((void *)&locFPFNum,(void *)&IFPFComp,sizeof(InternalFPF));
  1162. }
  1163.  
  1164. /*
  1165. ** Do the reverse of the above.  As long as the number is
  1166. ** greater than or equal to 10, divide it by 10.  Increment the
  1167. ** exponent counter for each multiplication.
  1168. */
  1169. while(1)
  1170. {
  1171.         AddSubInternalFPF(1,&locFPFNum,&IFPF10,&IFPFComp);
  1172.         if(IFPFComp.sign!=0) break;
  1173.         DivideInternalFPF(&locFPFNum,&IFPF10,&IFPFComp);
  1174.         expcount++;
  1175.         memcpy((void *)&locFPFNum,(void *)&IFPFComp,sizeof(InternalFPF));
  1176. }
  1177.  
  1178. /*
  1179. ** About time to start storing things.  First, store the
  1180. ** mantissa sign.
  1181. */
  1182. ccount=1;               /* Init character counter */
  1183. if(msign==0)
  1184.         *dest++='+';
  1185. else
  1186.         *dest++='-';
  1187.  
  1188. /*
  1189. ** At this point we know that the number is in the range
  1190. ** 10 > n >=1.  We need to "strip digits" out of the
  1191. ** mantissa.  We do this by treating the mantissa as
  1192. ** an integer and multiplying by 10. (Not a floating-point
  1193. ** 10, but an integer 10.  Since this is debug code and we
  1194. ** could care less about speed, we'll do it the stupid
  1195. ** way and simply add the number to itself 10 times.
  1196. ** Anything that makes it to the left of the implied binary point
  1197. ** gets stripped off and emitted.  We'll do this for
  1198. ** 5 significant digits (which should be enough to
  1199. ** verify things).
  1200. */
  1201. /*
  1202. ** Re-position radix point
  1203. */
  1204. carryaccum=0;
  1205. while(locFPFNum.exp>0)
  1206. {
  1207.         mycarry=0;
  1208.         ShiftMantLeft1(&mycarry,locFPFNum.mantissa);
  1209.         carryaccum=(carryaccum<<1);
  1210.         if(mycarry) carryaccum++;
  1211.         locFPFNum.exp--;
  1212. }
  1213.  
  1214. while(locFPFNum.exp<0)
  1215. {
  1216.         mycarry=0;
  1217.         ShiftMantRight1(&mycarry,locFPFNum.mantissa);
  1218.         locFPFNum.exp++;
  1219. }
  1220.  
  1221. for(i=0;i<6;i++)
  1222.         if(i==1)
  1223.         {       /* Emit decimal point */
  1224.                 *dest++='.';
  1225.                 ccount++;
  1226.         }
  1227.         else
  1228.         {       /* Emit a digit */
  1229.                 *dest++=('0'+carryaccum);
  1230.                 ccount++;
  1231.  
  1232.                 carryaccum=0;
  1233.                 memcpy((void *)&IFPF10,
  1234.                         (void *)&locFPFNum,
  1235.                         sizeof(InternalFPF));
  1236.  
  1237.                 /* Do multiply via repeated adds */
  1238.                 for(j=0;j<9;j++)
  1239.                 {
  1240.                         mycarry=0;
  1241.                         for(k=(INTERNAL_FPF_PRECISION-1);k>=0;k--)              
  1242.                                 Add16Bits(&mycarry,&(IFPFComp.mantissa[k]),
  1243.                                         locFPFNum.mantissa[k],
  1244.                                         IFPF10.mantissa[k]);
  1245.                         carryaccum+=mycarry ? 1 : 0;
  1246.                         memcpy((void *)&locFPFNum,
  1247.                                 (void *)&IFPFComp,
  1248.                                 sizeof(InternalFPF));
  1249.                 }
  1250.         }
  1251.         
  1252. /*
  1253. ** Now move the 'E', the exponent sign, and the exponent
  1254. ** into the string.
  1255. */
  1256. *dest++='E';
  1257.  
  1258. ccount+=sprintf(dest,"%4d",expcount);
  1259.  
  1260. /*
  1261. ** All done, go home.
  1262. */
  1263. return(ccount);
  1264.  
  1265. }
  1266.